package cn.tedu.mall.common;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

public class CodeCounter {

    public static String srcDirectoryPath = "D:/IdeaProjects/csmall-repo";
    // public static String srcDirectoryPath = "/Users/chengheng/Documents/Workspace/Intellij_IDEA/csmall-repo";

    public static List<JavaFileInfo> javaFileInfoList = new ArrayList<>();
    public static List<XmlFileInfo> xmlFileInfoList = new ArrayList<>();
    public static List<YmlFileInfo> ymlFileInfoList = new ArrayList<>();
    public static List<SqlFileInfo> sqlFileInfoList = new ArrayList<>();
    public static List<File> otherFileList = new ArrayList<>();

    public static List<String> ignoreNameList = new ArrayList<>();

    static {
        ignoreNameList.add("target");
        ignoreNameList.add(".idea");
        ignoreNameList.add(".mvn");
        ignoreNameList.add("CodeCounter.java");
    }

    public static void main(String[] args) throws Exception {
        File srcDirectory = new File(srcDirectoryPath);
        if (!srcDirectory.exists()) {
            System.out.println("源文件夹不存在！结束！");
            return;
        }

        File[] subFiles = srcDirectory.listFiles();
        if (subFiles.length == 0) {
            System.out.println("源文件夹为空！结束！");
            return;
        }

        readDirectory(srcDirectory);

        printFileInfo();

        //printFileList();
    }

    public static void printFileInfo() {
        int countOfJavaFile = 0;
        int countOfXmlFile = 0;
        int countOfYmlFile = 0;
        int countOfSqlFile = 0;
        int countOfJavaPackageStatementLines = 0;
        int countOfJavaImportStatementLines = 0;
        int countOfJavaCommentStatementLines = 0;
        int countOfXmlCommentStatementLines = 0;
        int countOfYmlCommentStatementLines = 0;
        int countOfSqlCommentStatementLines = 0;
        int countOfJavaStatementLines = 0;
        int countOfXmlStatementLines = 0;
        int countOfYmlStatementLines = 0;
        int countOfSqlStatementLines = 0;
        int countOfJavaBlankLines = 0;
        int countOfXmlBlankLines = 0;
        int countOfYmlBlankLines = 0;
        int countOfSqlBlankLines = 0;
        int countOfJavaLines = 0;
        int countOfXmlLines = 0;
        int countOfYmlLines = 0;
        int countOfSqlLines = 0;

        for (JavaFileInfo javaFileInfo : javaFileInfoList) {
            countOfJavaFile++;
            countOfJavaPackageStatementLines += javaFileInfo.countOfPackageStatementLines;
            countOfJavaImportStatementLines += javaFileInfo.countOfImportStatementLines;
            countOfJavaCommentStatementLines += javaFileInfo.countOfCommentStatementLines;
            countOfJavaStatementLines += javaFileInfo.countOfJavaStatementLines;
            countOfJavaBlankLines += javaFileInfo.countOfBlankLines;
        }
        for (XmlFileInfo xmlFileInfo : xmlFileInfoList) {
            countOfXmlFile++;
            countOfXmlStatementLines += xmlFileInfo.countOfXmlStatementLines;
            countOfXmlCommentStatementLines += xmlFileInfo.countOfCommentStatementLines;
            countOfXmlBlankLines += xmlFileInfo.countOfBlankLines;
        }
        for (YmlFileInfo ymlFileInfo : ymlFileInfoList) {
            countOfYmlFile++;
            countOfYmlStatementLines += ymlFileInfo.countOfYmlStatementLines;
            countOfYmlCommentStatementLines += ymlFileInfo.countOfCommentStatementLines;
            countOfYmlBlankLines += ymlFileInfo.countOfBlankLines;
        }
        for (SqlFileInfo sqlFileInfo : sqlFileInfoList) {
            countOfSqlFile++;
            countOfSqlStatementLines += sqlFileInfo.countOfSqlStatementLines;
            countOfSqlCommentStatementLines += sqlFileInfo.countOfCommentStatementLines;
            countOfSqlBlankLines += sqlFileInfo.countOfBlankLines;
        }

        countOfJavaLines = sum(countOfJavaPackageStatementLines, countOfJavaImportStatementLines, countOfJavaCommentStatementLines, countOfJavaStatementLines, countOfJavaBlankLines);
        countOfXmlLines = sum(countOfXmlStatementLines, countOfXmlCommentStatementLines, countOfXmlBlankLines);
        countOfYmlLines = sum(countOfYmlStatementLines, countOfYmlCommentStatementLines, countOfYmlBlankLines);
        countOfSqlLines = sum(countOfSqlStatementLines, countOfSqlCommentStatementLines, countOfSqlBlankLines);

        System.out.println("Java文件数量：" + countOfJavaFile + "个。");
        System.out.println("Java文件总代码行数：" + countOfJavaLines + "行。");
        System.out.println("\tpackage语句：" + countOfJavaPackageStatementLines + "行。");
        System.out.println("\timport语句：" + countOfJavaImportStatementLines + "行。");
        System.out.println("\tJava语句：" + countOfJavaStatementLines + "行。");
        System.out.println("\t注释：" + countOfJavaCommentStatementLines + "行。");
        System.out.println("\t空白行：" + countOfJavaBlankLines + "行。");
        System.out.println("\t有效代码（Java语句 + 注释）：" + (countOfJavaStatementLines + countOfJavaCommentStatementLines) + "行。");
        System.out.println();
        System.out.println("Xml文件数量：" + countOfXmlFile + "个。");
        System.out.println("Xml文件总代码行数：" + countOfXmlLines + "行。");
        System.out.println("\tXml语句：" + countOfXmlStatementLines + "行。");
        System.out.println("\t注释：" + countOfXmlCommentStatementLines + "行。");
        System.out.println("\t空白行：" + countOfXmlBlankLines + "行。");
        System.out.println("\t有效代码（Xml语句 + 注释）：" + (countOfXmlStatementLines + countOfXmlCommentStatementLines) + "行。");
        System.out.println();
        System.out.println("Yml文件数量：" + countOfYmlFile + "个。");
        System.out.println("Yml文件总代码行数：" + countOfYmlLines + "行。");
        System.out.println("\tYml语句：" + countOfYmlStatementLines + "行。");
        System.out.println("\t注释：" + countOfYmlCommentStatementLines + "行。");
        System.out.println("\t空白行：" + countOfYmlBlankLines + "行。");
        System.out.println("\t有效代码（Yml语句 + 注释）：" + (countOfYmlStatementLines + countOfYmlCommentStatementLines) + "行。");
        System.out.println();
        System.out.println("Sql文件数量：" + countOfSqlFile + "个。");
        System.out.println("Sql文件总代码行数：" + countOfSqlLines + "行。");
        System.out.println("\tSql语句：" + countOfSqlStatementLines + "行。");
        System.out.println("\t注释：" + countOfSqlCommentStatementLines + "行。");
        System.out.println("\t空白行：" + countOfSqlBlankLines + "行。");
        System.out.println("\t有效代码（Sql语句 + 注释）：" + (countOfSqlStatementLines + countOfSqlCommentStatementLines) + "行。");
        System.out.println();
        System.out.println("总有效代码：" + sum(countOfJavaStatementLines, countOfJavaCommentStatementLines,
                countOfXmlStatementLines, countOfXmlCommentStatementLines,
                countOfYmlStatementLines, countOfYmlCommentStatementLines,
                countOfSqlStatementLines, countOfSqlCommentStatementLines) + "行。");
    }

    public static void printFileList() {
        String filePath = null;
        int lineNumber = 0;
        System.out.println("Java文件清单");
        for (JavaFileInfo fileInfo : javaFileInfoList) {
            filePath = fileInfo.file.getAbsolutePath()
                    .replace("/Users/chengheng/Documents/Workspace/Intellij_IDEA", "");
            lineNumber = fileInfo.countOfPackageStatementLines
                    + fileInfo.countOfImportStatementLines
                    + fileInfo.countOfCommentStatementLines
                    + fileInfo.countOfJavaStatementLines
                    + fileInfo.countOfBlankLines;
            System.out.println("\t" + filePath + " (" + lineNumber + ")");
        }
        System.out.println();

        System.out.println("Xml文件清单");
        for (XmlFileInfo fileInfo : xmlFileInfoList) {
            filePath = fileInfo.file.getAbsolutePath()
                    .replace("/Users/chengheng/Documents/Workspace/Intellij_IDEA", "");
            lineNumber = fileInfo.countOfXmlStatementLines
                    + fileInfo.countOfBlankLines;
            System.out.println("\t" + filePath + " (" + lineNumber + ")");
        }
        System.out.println();

        System.out.println("Yml文件清单");
        for (YmlFileInfo fileInfo : ymlFileInfoList) {
            filePath = fileInfo.file.getAbsolutePath()
                    .replace("/Users/chengheng/Documents/Workspace/Intellij_IDEA", "");
            lineNumber = fileInfo.countOfYmlStatementLines
                    + fileInfo.countOfBlankLines;
            System.out.println("\t" + filePath + " (" + lineNumber + ")");
        }
        System.out.println();

        System.out.println("Sql文件清单");
        for (SqlFileInfo fileInfo : sqlFileInfoList) {
            filePath = fileInfo.file.getAbsolutePath()
                    .replace("/Users/chengheng/Documents/Workspace/Intellij_IDEA", "");
            lineNumber = fileInfo.countOfSqlStatementLines
                    + fileInfo.countOfBlankLines;
            System.out.println("\t" + filePath + " (" + lineNumber + ")");
        }
        System.out.println();
    }

    public static void readDirectory(File directory) throws Exception {
        String directoryPath = directory.getAbsolutePath();
        for (String ignoreDirectoryName : ignoreNameList) {
            if (directoryPath.contains(ignoreDirectoryName)) {
                return;
            }
        }
        File[] subFiles = directory.listFiles();
        for (File file : subFiles) {
            if (file.isFile()) {
                readFileLines(file);
            } else {
                readDirectory(file);
            }
        }
    }

    public static void readFileLines(File file) throws Exception {
        String fileName = file.getName();
        FileReader fileReader = new FileReader(file);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String line;
        if (fileName.endsWith(".java")) {
            JavaFileInfo javaFileInfo = new JavaFileInfo();
            javaFileInfo.file = file;
            while ((line = bufferedReader.readLine()) != null) {
                line = line.trim();
                if (line.equals("")) {
                    javaFileInfo.countOfBlankLines++;
                } else if (line.startsWith("package ")) {
                    javaFileInfo.countOfPackageStatementLines++;
                } else if (line.startsWith("import ")) {
                    javaFileInfo.countOfImportStatementLines++;
                } else if (line.startsWith("//") || line.startsWith("/*") || line.startsWith("*")) {
                    javaFileInfo.countOfCommentStatementLines++;
                } else {
                    javaFileInfo.countOfJavaStatementLines++;
                }
            }
            javaFileInfoList.add(javaFileInfo);
        } else if (fileName.endsWith(".xml")) {
            XmlFileInfo xmlFileInfo = new XmlFileInfo();
            xmlFileInfo.file = file;
            while ((line = bufferedReader.readLine()) != null) {
                line = line.trim();
                if (line.equals("")) {
                    xmlFileInfo.countOfBlankLines++;
                } else if (line.startsWith("<!--")) {
                    xmlFileInfo.countOfCommentStatementLines++;
                } else {
                    xmlFileInfo.countOfXmlStatementLines++;
                }
            }
            xmlFileInfoList.add(xmlFileInfo);
        } else if (fileName.endsWith(".yml")) {
            YmlFileInfo ymlFileInfo = new YmlFileInfo();
            ymlFileInfo.file = file;
            while ((line = bufferedReader.readLine()) != null) {
                line = line.trim();
                if (line.equals("")) {
                    ymlFileInfo.countOfBlankLines++;
                } else if (line.startsWith("# ")) {
                    ymlFileInfo.countOfCommentStatementLines++;
                } else {
                    ymlFileInfo.countOfYmlStatementLines++;
                }
            }
            ymlFileInfoList.add(ymlFileInfo);
        } else if (fileName.endsWith(".sql")) {
            SqlFileInfo sqlFileInfo = new SqlFileInfo();
            sqlFileInfo.file = file;
            while ((line = bufferedReader.readLine()) != null) {
                line = line.trim();
                if (line.equals("")) {
                    sqlFileInfo.countOfBlankLines++;
                } else if (line.startsWith("--")) {
                    sqlFileInfo.countOfCommentStatementLines++;
                } else {
                    sqlFileInfo.countOfSqlStatementLines++;
                }
            }
            sqlFileInfoList.add(sqlFileInfo);
        } else {
            otherFileList.add(file);
        }
        bufferedReader.close();
    }

    public static int sum(int... numbers) {
        int sum = 0;
        for (int i = 0; i < numbers.length; i++) {
            sum += numbers[i];
        }
        return sum;
    }

    public static abstract class FileInfo {
        public File file;
        public int countOfBlankLines;
        public int countOfCommentStatementLines;
    }

    public static class JavaFileInfo extends FileInfo {
        public int countOfPackageStatementLines;
        public int countOfImportStatementLines;
        public int countOfJavaStatementLines;

        @Override
        public String toString() {
            return "JavaFileInfo{" +
                    "file=" + file +
                    ", countOfBlankLines=" + countOfBlankLines +
                    ", countOfCommentStatementLines=" + countOfCommentStatementLines +
                    ", countOfPackageStatementLines=" + countOfPackageStatementLines +
                    ", countOfImportStatementLines=" + countOfImportStatementLines +
                    ", countOfJavaStatementLines=" + countOfJavaStatementLines +
                    '}';
        }
    }

    public static class XmlFileInfo extends FileInfo {
        public int countOfXmlStatementLines;

        @Override
        public String toString() {
            return "XmlFileInfo{" +
                    "file=" + file +
                    ", countOfBlankLines=" + countOfBlankLines +
                    ", countOfCommentStatementLines=" + countOfCommentStatementLines +
                    ", countOfXmlStatementLines=" + countOfXmlStatementLines +
                    '}';
        }
    }

    public static class YmlFileInfo extends FileInfo {
        public int countOfYmlStatementLines;

        @Override
        public String toString() {
            return "YmlFileInfo{" +
                    "file=" + file +
                    ", countOfBlankLines=" + countOfBlankLines +
                    ", countOfCommentStatementLines=" + countOfCommentStatementLines +
                    ", countOfYmlStatementLines=" + countOfYmlStatementLines +
                    '}';
        }
    }

    public static class SqlFileInfo extends FileInfo {
        public int countOfSqlStatementLines;

        @Override
        public String toString() {
            return "SqlFileInfo{" +
                    "file=" + file +
                    ", countOfBlankLines=" + countOfBlankLines +
                    ", countOfCommentStatementLines=" + countOfCommentStatementLines +
                    ", countOfSqlStatementLines=" + countOfSqlStatementLines +
                    '}';
        }
    }

}